package ru.chaykin.viewobject.geometry;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import ru.chaykin.graphdrawers.Pen;
import ru.chaykin.primitives.Circle;
import ru.chaykin.viewobject.ViewObject;
import android.graphics.Color;

public class Geometry extends ViewObject {

	private static final float SEL_WIDTH = 5;
	private static final int SEL_COLOR = 0x4dff0000; //70% прозрачность

	private static final int BOUNDING_BOX_BUFF_SIZE = 6 * 3 * Float.SIZE / Byte.SIZE;
	private static final int BOUNDING_BOX_COUNT_POINTS = 6;
	
	private FloatBuffer geoBuff;
	
	private boolean selected = false;
	
	private Pen origPen; //Нормальный стиль объекта
	private Pen currPen; //Текущий стиль: выделенный или нормальный
	
	private static Pen selPen = new Pen(SEL_WIDTH, 0, SEL_COLOR); //Стиль вывода для выделенного объекта
	
	public Geometry(Circle boundCircle, Pen pen, int midIndex, FloatBuffer geoBuff) {
		this.boundCircle = boundCircle;
		origPen = pen;
		currPen = pen;
		this.midIndex = midIndex;
		this.geoBuff = geoBuff;
	}
	
	@Override
	public void draw(GL10 gl) {
		if (selected && isRegion()) {
			gl.glEnable(GL10.GL_STENCIL_TEST);
			gl.glEnable(GL10.GL_BLEND);
			gl.glClearStencil(0);
			gl.glClear(GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_STENCIL_BUFFER_BIT); 
		
			gl.glStencilFunc(GL10.GL_NEVER, 0, 1);
			gl.glStencilOp(GL10.GL_INVERT, GL10.GL_KEEP, GL10.GL_KEEP);
			// Рисуем многоугольник с помощью три фана
	    	int startPos = geoBuff.position();
	    	geoBuff.position(0);
	    	gl.glVertexPointer(3, GL10.GL_FLOAT, 0, geoBuff);
			gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, startPos / 3);
			geoBuff.position(startPos);
	
		    gl.glStencilFunc(GL10.GL_NOTEQUAL, 0, 1);
		    gl.glStencilOp(GL10.GL_KEEP, GL10.GL_KEEP, GL10.GL_ZERO);
		    
		    gl.glColor4f(Color.red(SEL_COLOR) / 256.0f, Color.green(SEL_COLOR) / 256.0f, Color.blue(SEL_COLOR) / 256.0f, Color.alpha(SEL_COLOR) / 256.0f);

		    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, bbox);
			gl.glDrawArrays(GL10.GL_TRIANGLES, 0, BOUNDING_BOX_COUNT_POINTS);
			gl.glDisable(GL10.GL_BLEND);
			gl.glDisable(GL10.GL_STENCIL_TEST);
		}
		drawBorder(gl);
	}
	
	private final void drawBorder(GL10 gl) {
		int startPos = geoBuff.position();
		int color = currPen.getColor();
		gl.glColor4f(Color.red(color) / 256.0f, Color.green(color) / 256.0f, Color.blue(color) / 256.0f, 0);
		gl.glLineWidth(currPen.getWidth());
		geoBuff.position(0);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, geoBuff);
		gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, startPos / 3);
		geoBuff.position(startPos);	// Да, я быдлокодер :(
	}
	
	private FloatBuffer bbox;
	
	public FloatBuffer getBuff() {
		return geoBuff;
	}

	@Override
	public void setSelected(boolean selected) {
		this.selected = selected;
		if (selected) {
			currPen = selPen;
			float minX = Float.MAX_VALUE;
			float minY = Float.MAX_VALUE;
			float maxX = Float.MIN_VALUE;
			float maxY = Float.MIN_VALUE;
			for (int i = 0; i < geoBuff.position(); i+=3) {
				float currX = geoBuff.get(i);
				float currY = geoBuff.get(i + 1);
				if (currX > maxX)
					maxX = currX;
				if (currY > maxY)
					maxY = currY;
				if (currX < minX)
					minX = currX;
				if (currY < minY)
					minY = currY;
			}
			ByteBuffer byteBuf = ByteBuffer.allocateDirect(BOUNDING_BOX_BUFF_SIZE);
			byteBuf.order(ByteOrder.nativeOrder());
			bbox = byteBuf.asFloatBuffer();
			bbox.put(minX);
			bbox.put(maxY);
			bbox.put(0);
			bbox.put(minX);
			bbox.put(minY);
			bbox.put(0);
			bbox.put(maxX);
			bbox.put(minY);
			bbox.put(0);
			bbox.put(minX);
			bbox.put(maxY);
			bbox.put(0);
			bbox.put(maxX);
			bbox.put(minY);
			bbox.put(0);
			bbox.put(maxX);
			bbox.put(maxY);
			bbox.put(0);
			bbox.position(0);
		}
		else {
			currPen = origPen;
			bbox = null; //Экономим память слегка
		}
	}

	@Override
	public boolean isRegion() {
		int pos = geoBuff.position();
		return geoBuff.get(0) == geoBuff.get(pos - 3) && geoBuff.get(1) == geoBuff.get(pos - 2) && geoBuff.get(2) == geoBuff.get(pos - 1);
	}
}
